﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace SpaceGame
{
    public delegate void ProduceObjectsDelegate();

    public class Engine
    {
        IRenderer renderer;
        public IInputDevice inputDevice;
        List<GameObject> allObjects;
        PlayerSpaceShip playerSpaceShip;
        public ProduceObjectsDelegate ProduceEnemies;

        public int TotalTime { get; private set; }
        public event EventHandler GameOver;

        int gameLoopWaitTime;
        private bool isTerminated;

        public Engine(IRenderer renderer, IInputDevice userInterface, int gameLoopWaitTime)
        {
            this.renderer = renderer;
            this.inputDevice = userInterface;
            this.allObjects = new List<GameObject>();
            this.gameLoopWaitTime = gameLoopWaitTime;
            this.TotalTime = 0;
        }

        public PlayerSpaceShip PlayerSpaceShip
        {
            get
            {
                return this.playerSpaceShip;
            }
        }

        public void AddPlayerSpaceShip(PlayerSpaceShip ship)
        {
            if (ship == null)
            {
                throw new ArgumentNullException("ship");
            }

            this.playerSpaceShip = ship;
            allObjects.Add(ship);
        }

        public void AddObject(GameObject obj)
        {
            if (obj == null)
            {
                throw new ArgumentNullException("obj");
            }
            
            allObjects.Add(obj);
        }

        public void Run()
        {
            isTerminated = false;

            Timer timer = new Timer((e) => this.TotalTime++, null, 0, 1000);

            while (!isTerminated)
            {
                if (this.PlayerSpaceShip.IsDestroyed == true)
                {
                    isTerminated = true;
                    timer.Dispose();
                }

                this.renderer.FlushBuffer();

                Thread.Sleep(this.gameLoopWaitTime);

                this.inputDevice.ProcessInput();

                this.renderer.ClearBuffer();

                this.ProduceEnemies();

                // WARNING!! not optimized, might become slow
                var objectsToAdd = new List<GameObject>();

                foreach (var obj in this.allObjects)
                {
                    foreach (var created in obj.CreateObjects())
                    {
                        objectsToAdd.Add(created);
                    }
                }

                foreach (var obj in objectsToAdd)
                {
                    this.AddObject(obj);
                }

                foreach (var obj in this.allObjects)
                {
                    obj.Update();

                    this.renderer.AddToBuffer(obj);

                    //foreach (var created in obj.CreateObjects())
                    //{
                    //    created.Update();
                    //    //this.AddObject(created);
                    //    this.renderer.AddToBuffer(created);
                    //}

                }

                CollisionManager.ManageCollisions(this.allObjects);
              
                this.allObjects.RemoveAll(obj => obj.IsDestroyed);
            }

            OnGameOver();
        }

        private void OnGameOver()
        {
            if (this.GameOver != null)
            {
                this.GameOver(this, EventArgs.Empty);
            }
        }

        public void UpdateSpaceShip()
        {
 
        }

        public virtual void MoveToLeft()
        {
            this.playerSpaceShip.MoveLeft();
        }

        public virtual void MoveToRight()
        {
            this.playerSpaceShip.MoveRight();
        }

        public virtual void MoveToUp()
        {
            this.playerSpaceShip.MoveUp();
        }

        public virtual void MoveToDown()
        {
            this.playerSpaceShip.MoveDown();
        }

        public void Stop()
        {
            isTerminated = true;
        }

    }
}
